home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / FLTK-1.0.6 / fluid / file.cxx < prev    next >
Encoding:
C/C++ Source or Header  |  1999-03-04  |  14.1 KB  |  597 lines

  1. //
  2. // "$Id: file.cxx,v 1.7 1999/03/04 18:10:00 mike Exp $"
  3. //
  4. // Fluid file routines for the Fast Light Tool Kit (FLTK).
  5. //
  6. // You may find the basic read_* and write_* routines to
  7. // be useful for other programs.  I have used them many times.
  8. // They are somewhat similar to tcl, using matching { and }
  9. // to quote strings.
  10. //
  11. // Copyright 1998-1999 by Bill Spitzak and others.
  12. //
  13. // This library is free software; you can redistribute it and/or
  14. // modify it under the terms of the GNU Library General Public
  15. // License as published by the Free Software Foundation; either
  16. // version 2 of the License, or (at your option) any later version.
  17. //
  18. // This library is distributed in the hope that it will be useful,
  19. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  21. // Library General Public License for more details.
  22. //
  23. // You should have received a copy of the GNU Library General Public
  24. // License along with this library; if not, write to the Free Software
  25. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  26. // USA.
  27. //
  28. // Please report all bugs and problems to "fltk-bugs@easysw.com".
  29. //
  30.  
  31. #include <ctype.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <stdarg.h>
  36. #include "alignment_panel.h"
  37.  
  38. ////////////////////////////////////////////////////////////////
  39. // BASIC FILE WRITING:
  40.  
  41. static FILE *fout;
  42.  
  43. int open_write(const char *s) {
  44.   if (!s) {fout = stdout; return 1;}
  45.   FILE *f = fopen(s,"w");
  46.   if (!f) return 0;
  47.   fout = f;
  48.   return 1;
  49. }
  50.  
  51. int close_write() {
  52.   if (fout != stdout) {
  53.     int x = fclose(fout);
  54.     fout = stdout;
  55.     return x >= 0;
  56.   }
  57.   return 1;
  58. }
  59.  
  60. static int needspace;
  61. int is_id(char); // in code.C
  62.  
  63. // write a string, quoting characters if necessary:
  64. void write_word(const char *w) {
  65.   if (needspace) putc(' ', fout);
  66.   needspace = 1;
  67.   if (!w || !*w) {fprintf(fout,"{}"); return;}
  68.   const char *p;
  69.   // see if it is a single word:
  70.   for (p = w; is_id(*p); p++) ;
  71.   if (!*p) {fprintf(fout,"%s",w); return;}
  72.   // see if there are matching braces:
  73.   int n = 0;
  74.   for (p = w; *p; p++) {
  75.     if (*p == '{') n++;
  76.     else if (*p == '}') {n--; if (n<0) break;}
  77.   }
  78.   int mismatched = (n != 0);
  79.   // write out brace-quoted string:
  80.   putc('{', fout);
  81.   for (; *w; w++) {
  82.     switch (*w) {
  83.     case '{':
  84.     case '}':
  85.       if (!mismatched) break;
  86.     case '\\':
  87.     case '#':
  88.       putc('\\',fout);
  89.       break;
  90.     }
  91.     putc(*w,fout);
  92.   }
  93.   putc('}', fout);
  94. }
  95.  
  96. // write an arbitrary formatted word, or a comment, etc:
  97. void write_string(const char *format, ...) {
  98.   va_list args;
  99.   va_start(args, format);
  100.   if (needspace) fputc(' ',fout);
  101.   vfprintf(fout, format, args);
  102.   va_end(args);
  103.   needspace = !isspace(format[strlen(format)-1]);
  104. }
  105.  
  106. // start a new line and indent it for a given nesting level:
  107. void write_indent(int n) {
  108.   fputc('\n',fout);
  109.   while (n--) {fputc(' ',fout); fputc(' ',fout);}
  110.   needspace = 0;
  111. }
  112.  
  113. // write a '{' at the given indenting level:
  114. void write_open(int) {
  115.   if (needspace) fputc(' ',fout);
  116.   fputc('{',fout);
  117.   needspace = 0;
  118. }
  119.  
  120. // write a '}' at the given indenting level:
  121. void write_close(int n) {
  122.   if (needspace) write_indent(n);
  123.   fputc('}',fout);
  124.   needspace = 1;
  125. }
  126.  
  127. ////////////////////////////////////////////////////////////////
  128. // BASIC FILE READING:
  129.  
  130. static FILE *fin;
  131. static int lineno;
  132. static const char *fname;
  133.  
  134. int open_read(const char *s) {
  135.   lineno = 1;
  136.   if (!s) {fin = stdin; fname = "stdin"; return 1;}
  137.   FILE *f = fopen(s,"r");
  138.   if (!f) return 0;
  139.   fin = f;
  140.   fname = s;
  141.   return 1;
  142. }
  143.  
  144. int close_read() {
  145.   if (fin != stdin) {
  146.     int x = fclose(fin);
  147.     fin = 0;
  148.     return x >= 0;
  149.   }
  150.   return 1;
  151. }
  152.  
  153. #include <FL/fl_message.H>
  154.  
  155. void read_error(const char *format, ...) {
  156.   va_list args;
  157.   va_start(args, format);
  158.   if (!fin) {
  159.     char buffer[1024];
  160.     vsprintf(buffer, format, args);
  161.     fl_message(buffer);
  162.   } else {
  163.     fprintf(stderr, "%s:%d: ", fname, lineno);
  164.     vfprintf(stderr, format, args);
  165.     fprintf(stderr, "\n");
  166.   }
  167.   va_end(args);
  168. }
  169.  
  170. static int hexdigit(int x) {
  171.   if (isdigit(x)) return x-'0';
  172.   if (isupper(x)) return x-'A'+10;
  173.   if (islower(x)) return x-'a'+10;
  174.   return 20;
  175. }
  176.  
  177.  
  178. static int read_quoted() {    // read whatever character is after a \ .
  179.   int c,d,x;
  180.   switch(c = fgetc(fin)) {
  181.   case '\n': lineno++; return -1;
  182.   case 'a' : return('\a');
  183.   case 'b' : return('\b');
  184.   case 'f' : return('\f');
  185.   case 'n' : return('\n');
  186.   case 'r' : return('\r');
  187.   case 't' : return('\t');
  188.   case 'v' : return('\v');
  189.   case 'x' :    /* read hex */
  190.     for (c=x=0; x<3; x++) {
  191.       int ch = fgetc(fin);
  192.       d = hexdigit(ch);
  193.       if (d > 15) {ungetc(ch,fin); break;}
  194.       c = (c<<4)+d;
  195.     }
  196.     break;
  197.   default:        /* read octal */
  198.     if (c<'0' || c>'7') break;
  199.     c -= '0';
  200.     for (x=0; x<2; x++) {
  201.       int ch = fgetc(fin);
  202.       d = hexdigit(ch);
  203.       if (d>7) {ungetc(ch,fin); break;}
  204.       c = (c<<3)+d;
  205.     }
  206.     break;
  207.   }
  208.   return(c);
  209. }
  210.  
  211. // return a word read from the file, or NULL at the EOF:
  212. // This will skip all comments (# to end of line), and evaluate
  213. // all \xxx sequences and use \ at the end of line to remove the newline.
  214. // A word is any one of:
  215. //    a continuous string of non-space chars except { and } and #
  216. //    everything between matching {...} (unless wantbrace != 0)
  217. //    the characters '{' and '}'
  218.  
  219. static char *buffer;
  220. static int buflen;
  221. static void expand_buffer(int length) {
  222.   if (length >= buflen) {
  223.     if (!buflen) {
  224.       buflen = length+1;
  225.       buffer = (char*)malloc(buflen);
  226.     } else {
  227.       buflen = 2*buflen;
  228.       if (length >= buflen) buflen = length+1;
  229.       buffer = (char *)realloc((void *)buffer,buflen);
  230.     }
  231.   }
  232. }
  233.  
  234. const char *read_word(int wantbrace) {
  235.   int x;
  236.  
  237.   // skip all the whitespace before it:
  238.   for (;;) {
  239.     x = getc(fin);
  240.     if (x < 0) {    // eof
  241.       return 0;
  242.     } else if (x == '#') {    // comment
  243.       do x = getc(fin); while (x >= 0 && x != '\n');
  244.       lineno++;
  245.       continue;
  246.     } else if (x == '\n') {
  247.       lineno++;
  248.     } else if (!isspace(x)) {
  249.       break;
  250.     }
  251.   }
  252.  
  253.   expand_buffer(100);
  254.  
  255.   if (x == '{' && !wantbrace) {
  256.  
  257.     // read in whatever is between braces
  258.     int length = 0;
  259.     int nesting = 0;
  260.     for (;;) {
  261.       x = getc(fin);
  262.       if (x<0) {read_error("Missing '}'"); break;}
  263.       else if (x == '#') { // embedded comment
  264.     do x = getc(fin); while (x >= 0 && x != '\n');
  265.     lineno++;
  266.     continue;
  267.       } else if (x == '\n') lineno++;
  268.       else if (x == '\\') {x = read_quoted(); if (x<0) continue;}
  269.       else if (x == '{') nesting++;
  270.       else if (x == '}') {if (!nesting--) break;}
  271.       buffer[length++] = x;
  272.       expand_buffer(length);
  273.     }
  274.     buffer[length] = 0;
  275.     return buffer;
  276.  
  277.   } else if (x == '{' || x == '}') {
  278.     // all the punctuation is a word:
  279.     buffer[0] = x;
  280.     buffer[1] = 0;
  281.     return buffer;
  282.  
  283.   } else {
  284.  
  285.     // read in an unquoted word:
  286.     int length = 0;
  287.     for (;;) {
  288.       if (x == '\\') {x = read_quoted(); if (x<0) continue;}
  289.       else if (x<0 || isspace(x) || x=='{' || x=='}' || x=='#') break;
  290.       buffer[length++] = x;
  291.       expand_buffer(length);
  292.       x = getc(fin);
  293.     }
  294.     ungetc(x, fin);
  295.     buffer[length] = 0;
  296.     return buffer;
  297.  
  298.   }
  299. }
  300.  
  301. ////////////////////////////////////////////////////////////////
  302.  
  303. #include <FL/Fl.H>
  304. #include "Fl_Widget_Type.h"
  305.  
  306. // global int variables:
  307. extern int gridx, gridy, snap;
  308. static struct {const char* name; int* value;} inttable[] = {
  309.   {"gridx", &gridx},
  310.   {"gridy", &gridy},
  311.   {"snap", &snap}
  312. };
  313.  
  314.  
  315. extern int header_file_set;
  316. extern int code_file_set;
  317. extern const char* header_file_name;
  318. extern const char* code_file_name;
  319.  
  320. int write_file(const char *filename, int selected_only) {
  321.   if (!open_write(filename)) return 0;
  322.   write_string("# data file for the Fltk User Interface Designer (fluid)\n"
  323.            "version %.2f",FL_VERSION);
  324.   if(!include_H_from_C)
  325.     write_string("\ndo_not_include_H_from_C");
  326.   if (!selected_only) {
  327.     write_string("\nheader_name"); write_word(header_file_name);
  328.     write_string("\ncode_name"); write_word(code_file_name);
  329.     for (unsigned int i=0; i<sizeof(inttable)/sizeof(*inttable); i++)
  330.       write_string("\n%s %d",inttable[i].name, *inttable[i].value);
  331.   }
  332.   for (Fl_Type *p = Fl_Type::first; p;) {
  333.     if (!selected_only || p->selected) {
  334.       p->write();
  335.       write_string("\n");
  336.       int q = p->level;
  337.       for (p = p->next; p && p->level > q; p = p->next);
  338.     } else {
  339.       p = p->next;
  340.     }
  341.   }
  342.   return close_write();
  343. }
  344.  
  345. ////////////////////////////////////////////////////////////////
  346. // read all the objects out of the input file:
  347.  
  348. void read_fdesign();
  349.  
  350. double read_version;
  351.  
  352. extern Fl_Type *Fl_Type_make(const char *tn);
  353.  
  354. static void read_children(Fl_Type *p, int paste) {
  355.   Fl_Type::current = p;
  356.   for (;;) {
  357.     unsigned int i;
  358.     const char *c = read_word();
  359.   REUSE_C:
  360.     if (!c) {
  361.       if (p && !paste) read_error("Missing '}'");
  362.       break;
  363.     }
  364.  
  365.     if (!strcmp(c,"}")) {
  366.       if (!p) read_error("Unexpected '}'");
  367.       break;
  368.     }
  369.  
  370.     // this is the first word in a .fd file:
  371.     if (!strcmp(c,"Magic:")) {
  372.       read_fdesign();
  373.       return;
  374.     }
  375.  
  376.     if (!strcmp(c,"version")) {
  377.       c = read_word();
  378.       read_version = strtod(c,0);
  379.       if (read_version<=0 || read_version>FL_VERSION)
  380.     read_error("unknown version '%s'",c);
  381.       continue;
  382.     }
  383.  
  384.     // back compatability with Vincent Penne's original class code:
  385.     if (!p && !strcmp(c,"define_in_struct")) {
  386.       Fl_Type *t = Fl_Type_make("class");
  387.       t->name(read_word());
  388.       Fl_Type::current = p = t;
  389.       paste = 1; // stops "missing }" error
  390.       continue;
  391.     }
  392.  
  393.     if (!strcmp(c,"do_not_include_H_from_C"))
  394.     {
  395.       include_H_from_C=0;
  396.       goto CONTINUE;
  397.     }
  398.     if (!strcmp(c,"header_name")) {
  399.       if (!header_file_set) header_file_name = strdup(read_word());
  400.       else read_word();
  401.       goto CONTINUE;
  402.     }
  403.  
  404.     if (!strcmp(c,"code_name")) {
  405.       if (!code_file_set) code_file_name = strdup(read_word());
  406.       else read_word();
  407.       goto CONTINUE;
  408.     }
  409.  
  410.     for (i=0; i<sizeof(inttable)/sizeof(*inttable); i++) {
  411.       if (!strcmp(c,inttable[i].name)) {
  412.     c = read_word();
  413.     *inttable[i].value = atoi(c);
  414.     goto CONTINUE;
  415.       }
  416.     }
  417.  
  418.     {Fl_Type *t = Fl_Type_make(c);
  419.     if (!t) {
  420.       read_error("Unknown word \"%s\"", c);
  421.       continue;
  422.     }
  423.     t->name(read_word());
  424.  
  425.     c = read_word(1);
  426.     if (strcmp(c,"{")) {
  427.       read_error("Missing property list for %s\n",t->title());
  428.       goto REUSE_C;
  429.     }
  430.  
  431.     t->open_ = 0;
  432.     for (;;) {
  433.       const char *c = read_word();
  434.       if (!c || !strcmp(c,"}")) break;
  435.       t->read_property(c);
  436.     }
  437.  
  438.     if (!t->is_parent()) continue;
  439.     c = read_word(1);
  440.     if (strcmp(c,"{")) {
  441.       read_error("Missing child list for %s\n",t->title());
  442.       goto REUSE_C;
  443.     }
  444.     read_children(t, 0);}
  445.     Fl_Type::current = p;
  446.   CONTINUE:;
  447.   }
  448. }
  449.  
  450. extern void deselect();
  451.  
  452. int read_file(const char *filename, int merge) {
  453.   read_version = 0.0;
  454.   if (!open_read(filename)) return 0;
  455.   if (merge) deselect(); else    delete_all();
  456.   read_children(Fl_Type::current, merge);
  457.   Fl_Type::current = 0;
  458.   for (Fl_Type *o = Fl_Type::first; o; o = o->next)
  459.     if (o->selected) {Fl_Type::current = o; break;}
  460.   return close_read();
  461. }
  462.  
  463. ////////////////////////////////////////////////////////////////
  464. // Read Forms and XForms fdesign files:
  465.  
  466. int read_fdesign_line(const char*& name, const char*& value) {
  467.  
  468.   int length = 0;
  469.   int x;
  470.   // find a colon:
  471.   for (;;) {
  472.     x = getc(fin);
  473.     if (x < 0) return 0;
  474.     if (x == '\n') {length = 0; continue;} // no colon this line...
  475.     if (!isspace(x)) {
  476.       buffer[length++] = x;
  477.       expand_buffer(length);
  478.     }
  479.     if (x == ':') break;
  480.   }
  481.   int valueoffset = length;
  482.   buffer[length-1] = 0;
  483.  
  484.   // skip to start of value:
  485.   for (;;) {
  486.     x = getc(fin);
  487.     if (x < 0 || x == '\n' || !isspace(x)) break;
  488.   }
  489.  
  490.   // read the value:
  491.   for (;;) {
  492.     if (x == '\\') {x = read_quoted(); if (x<0) continue;}
  493.     else if (x == '\n') break;
  494.     buffer[length++] = x;
  495.     expand_buffer(length);
  496.     x = getc(fin);
  497.   }
  498.   buffer[length] = 0;
  499.   name = buffer;
  500.   value = buffer+valueoffset;
  501.   return 1;
  502. }
  503.  
  504. int fdesign_flip;
  505. int fdesign_magic;
  506. #include <FL/Fl_Group.H>
  507.  
  508. static const char *class_matcher[] = {
  509. "FL_CHECKBUTTON", "Fl_Check_Button",
  510. "FL_ROUNDBUTTON", "Fl_Round_Button",
  511. "FL_ROUND3DBUTTON", "Fl_Round_Button",
  512. "FL_LIGHTBUTTON", "Fl_Light_Button",
  513. "FL_FRAME", "Fl_Box",
  514. "FL_LABELFRAME", "Fl_Box",
  515. "FL_TEXT", "Fl_Box",
  516. "FL_VALSLIDER", "Fl_Value_Slider",
  517. "FL_MENU", "Fl_Menu_Button",
  518. "3", "FL_BITMAP",
  519. "1", "FL_BOX",
  520. "71","FL_BROWSER",
  521. "11","FL_BUTTON",
  522. "4", "FL_CHART",
  523. "42","FL_CHOICE",
  524. "61","FL_CLOCK",
  525. "25","FL_COUNTER",
  526. "22","FL_DIAL",
  527. "101","FL_FREE",
  528. "31","FL_INPUT",
  529. "12","Fl_Light_Button",
  530. "41","FL_MENU",
  531. "23","FL_POSITIONER",
  532. "13","Fl_Round_Button",
  533. "21","FL_SLIDER",
  534. "2", "FL_BOX", // was FL_TEXT
  535. "62","FL_TIMER",
  536. "24","Fl_Value_Slider",
  537. 0};
  538.  
  539. void read_fdesign() {
  540.   fdesign_magic = atoi(read_word());
  541.   fdesign_flip = (fdesign_magic < 13000);
  542.   Fl_Widget_Type *window = 0;
  543.   Fl_Widget_Type *group = 0;
  544.   Fl_Widget_Type *widget = 0;
  545.   if (!Fl_Type::current) {
  546.     Fl_Type *t = Fl_Type_make("Function");
  547.     t->name("create_the_forms()");
  548.     Fl_Type::current = t;
  549.   }
  550.   for (;;) {
  551.     const char *name;
  552.     const char *value;
  553.     if (!read_fdesign_line(name, value)) break;
  554.  
  555.     if (!strcmp(name,"Name")) {
  556.  
  557.       window = (Fl_Widget_Type*)Fl_Type_make("Fl_Window");
  558.       window->name(value);
  559.       window->label(value);
  560.       Fl_Type::current = widget = window;
  561.  
  562.     } else if (!strcmp(name,"class")) {
  563.  
  564.       if (!strcmp(value,"FL_BEGIN_GROUP")) {
  565.     group = widget = (Fl_Widget_Type*)Fl_Type_make("Fl_Group");
  566.     Fl_Type::current = group;
  567.       } else if (!strcmp(value,"FL_END_GROUP")) {
  568.     if (group) {
  569.       Fl_Group* g = (Fl_Group*)(group->o);
  570.       g->begin();
  571.       g->forms_end();
  572.       Fl_Group::current(0);
  573.     }
  574.     group = widget = 0;
  575.     Fl_Type::current = window;
  576.       } else {
  577.     for (int i = 0; class_matcher[i]; i += 2)
  578.       if (!strcmp(value,class_matcher[i])) {
  579.         value = class_matcher[i+1]; break;}
  580.     widget = (Fl_Widget_Type*)Fl_Type_make(value);
  581.     if (!widget) {
  582.       printf("class %s not found, using Fl_Button\n", value);
  583.       widget = (Fl_Widget_Type*)Fl_Type_make("Fl_Button");
  584.     }
  585.       }
  586.  
  587.     } else if (widget) {
  588.       if (!widget->read_fdesign(name, value))
  589.     printf("Ignoring \"%s: %s\"\n", name, value);
  590.     }
  591.   }
  592. }
  593.  
  594. //
  595. // End of "$Id: file.cxx,v 1.7 1999/03/04 18:10:00 mike Exp $".
  596. //
  597.